// RegAllocator.h
// A general registers allocator for all translators

#ifndef REGALLOCATOR_H
#define REGALLOCATOR_H

#include "crossbit/common.h"

namespace crossbit {

		enum RegAccessMode
		{
				USE = 0,
				DEF
		};

		class VBlock;

		class RegAllocator{
				public:
						// callback of regSpillIn and regSpillOut, provided for corresponding translators
						typedef void (* CBOfSpillIn) (XTMemAddr mem, XTRegNum treg);
						typedef void (* CBOfSpillOut)(XTRegNum treg, XTMemAddr mem);

						// reg_to_reg
						typedef void (* CBOfRegToReg) (XTRegNum reg1, XTRegNum reg2);
				public:
						// when different translator initialize the reg allocator, they should specify their own
						// callback pointers for the reg allocator
						RegAllocator( XTUint8 num_regs, CBOfSpillIn cb_spill_in, CBOfSpillOut cb_spill_out, CBOfRegToReg cb_regtoreg )
						{ 
								ra_num_of_reg = num_regs;
								ra_cb_spill_in = cb_spill_in;
								ra_cb_spill_out = cb_spill_out;
								ra_cb_reg_to_reg = cb_regtoreg;
								// initialize the vinst seq
								vinst_seq = 0;
								ra_spill_pool = (XTInt32 *)UTIL::XTMalloc(60 * ra_num_of_reg * sizeof(XTInt32));
								UTIL::XTMemset((void *)ra_spill_pool, 0, 60 * ra_num_of_reg * sizeof(XTInt32));
						}


						virtual ~RegAllocator()
						{
								if (ra_spill_pool)
										UTIL::XTFree(ra_spill_pool);
						}

						virtual XTRegNum regAlloc(XTRegNum vreg, RegAccessMode mode) = 0;	        
						virtual XTRegNum regAllocForce(XTRegNum vreg, XTRegNum expect, RegAccessMode mode) = 0;
						virtual XTRegNum regAllocForceExcept(XTRegNum vreg, XTRegNum except, RegAccessMode mode) = 0;

						virtual void regAllocReserve(XTRegNum reg) = 0;
						virtual void regAllocRelease(XTRegNum reg) = 0;

						virtual void init(VBlock *vb) = 0;

						//for some trivial stuffs
						virtual void phaseTask()
						{}

						// In Reg allocator, we should maintain a vinst sequence to record the current VInst which are being encoding.
						virtual void incrementVinstSeq()
						{
								++vinst_seq;
						}

				protected:
						XTInt32 vinst_seq;
						XTRegNum ra_num_of_reg;
						XTInt32 *ra_spill_pool;

						CBOfSpillIn ra_cb_spill_in;
						CBOfSpillOut ra_cb_spill_out;		
						CBOfRegToReg ra_cb_reg_to_reg;

						virtual void regSpillIn(XTRegNum vreg, XTRegNum treg)
						{
								(*ra_cb_spill_in)((XTMemAddr)(ra_spill_pool+vreg), treg);
						}

						// Spill out the allocated target reg for the vreg
						virtual XTRegNum regSpillOut(XTRegNum vreg) = 0;

						// ========================================
						// virtual registers status
						// ========================================
						const static XTInt32 UNMAPPED 		= 0x01;
						const static XTInt32 MAPPED 		= 0x02;
						// already mapped but have been spilled into memory
						const static XTInt32 SPILLED 		= 0x04;

						// ========================================
						// target register status
						// ========================================
						const static XTInt32 FREE			= 0x01;
						const static XTInt32 ALLOCATED		= 0x02;
						const static XTInt32 RESERVED		= 0x04; 

						// ========================================
						// this struct is used by both of the virtual
						// registers and target registers tables, to
						// record the regs' information which are now
						// under use.
						// ========================================
						struct RegUsage {
								XTInt32 status;
								XTRegNum mapped_to;		// mappted target register number
								XTUint32	inst;		// the num of the instruction belonged to
						};


		};

}

#endif
